package com.boot.mall.product.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.boot.common.constant.ProductConstant;
import com.boot.common.to.HasStockTo;
import com.boot.common.to.SkuReductionTo;
import com.boot.common.to.SpuBoundTo;
import com.boot.common.to.es.SkuEsModel;
import com.boot.common.utils.R;
import com.boot.mall.product.entity.*;
import com.boot.mall.product.feign.CouponFeignService;
import com.boot.mall.product.feign.SearchFeignService;
import com.boot.mall.product.feign.WareFeignService;
import com.boot.mall.product.service.*;
import com.boot.mall.product.vo.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.boot.common.utils.PageUtils;
import com.boot.common.utils.Query;

import com.boot.mall.product.dao.SpuInfoDao;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;


@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {

    @Autowired
    private SpuInfoDescService spuInfoDescService;
    @Autowired
    private SpuImagesService spuImagesService;
    @Autowired
    private ProductAttrValueService productAttrValueService;
    @Autowired
    private SkuInfoService skuInfoService;
    @Autowired
    private SkuImagesService skuImagesService;
    @Autowired
    private SkuSaleAttrValueService skuSaleAttrValueService;

    // 远程调用接口
    @Autowired
    private CouponFeignService couponFeignService;
    @Autowired
    private WareFeignService wareFeignService;
    @Autowired
    private SearchFeignService searchFeignService;

    @Autowired
    private BrandService brandService;
    @Autowired
    private CategoryService categoryService;
    @Autowired
    private AttrService attrService;

    // 保存Spu的信息  TODO 高级部分待完善
    @Override
    @Transactional      //开启事务
    public void saveSpuInfo(SpuSaveVo vo) {

        // 1、保存spu的基本信息 pms_spu_info
        SpuInfoEntity spuInfoEntity = new SpuInfoEntity();
        //将vo里的值赋值给spuInfo
        BeanUtils.copyProperties(vo,spuInfoEntity);
        //设置创建时间和修改时间
        spuInfoEntity.setCreateTime(new Date());
        spuInfoEntity.setUpdateTime(new Date());
        //执行保存
        baseMapper.insert(spuInfoEntity);

        // 2、保存spu的描述图片，保存的是图片地址 pms_spu_info_desc
        List<String> decripts = vo.getDecript();
        SpuInfoDescEntity spuInfoDescEntity = new SpuInfoDescEntity();
        //将图片的地址转换成字符串形式，使用逗号进行分割
        spuInfoDescEntity.setDecript(String.join(",",decripts));
        spuInfoDescEntity.setSpuId(spuInfoEntity.getId());
        //执行保存方法
        spuInfoDescService.save(spuInfoDescEntity);

        // 3、保存spu的图片集 pms_spu_images
        List<String> images = vo.getImages();
        //调用保存方法
        spuImagesService.saveImages(spuInfoEntity.getId(),images);

        // 4、保存spu的规格参数 pms_sku_sale_attr_value
        List<BaseAttrs> baseAttrs = vo.getBaseAttrs();
        //批量保存规格参数，基本属性，传入spu_id
        productAttrValueService.saveBaseAttrs(baseAttrs,spuInfoEntity.getId());

        // 5、保存spu的积分信息 sms_spu_bounds
        Bounds bounds = vo.getBounds();
        SpuBoundTo spuBoundTo = new SpuBoundTo();
        spuBoundTo.setSpuId(spuInfoEntity.getId());
        spuBoundTo.setBuyBounds(bounds.getBuyBounds());
        spuBoundTo.setGrowBounds(bounds.getGrowBounds());
        R r = couponFeignService.saveBounds(spuBoundTo);
        if (r.getCode() != 0){
            log.error("远程保存积分信息失败！");
        }

        // 6、保存spu对应的sku信息
        List<Skus> skus = vo.getSkus();
        if (skus != null && skus.size() > 0) {
            skus.forEach(sku -> {
                //判断默认图片
                List<Images> skuImages = sku.getImages();
                String defaultImage = "";
                for (Images skuImage : skuImages) {
                    if (skuImage.getDefaultImg() == 1){
                        defaultImage = skuImage.getImgUrl();
                    }
                }
                SkuInfoEntity skuInfoEntity = new SkuInfoEntity();
                //设置品牌信息、三级分类、spu_id
                skuInfoEntity.setBrandId(spuInfoEntity.getBrandId());
                skuInfoEntity.setCatalogId(spuInfoEntity.getCatalogId());
                skuInfoEntity.setSpuId(spuInfoEntity.getId());
                skuInfoEntity.setSkuName(sku.getSkuName());
                skuInfoEntity.setPrice(sku.getPrice());
                skuInfoEntity.setSkuTitle(sku.getSkuTitle());
                skuInfoEntity.setSkuSubtitle(sku.getSkuSubtitle());
                skuInfoEntity.setSaleCount(0L);
                skuInfoEntity.setSkuDefaultImg(defaultImage);
                //    保存sku的基本信息  pms_sku_info
                skuInfoService.save(skuInfoEntity);
                //生成的sku的id
                Long skuId = skuInfoEntity.getSkuId();
                //    保存sku的图片信息  pms_sku_images
                skuImagesService.saveSkuImages(skuImages,skuId);
                //    保存sku的销售属性  pms_sku_sale_attr_value
                List<Attr> attr = sku.getAttr();
                skuSaleAttrValueService.saveSkuAttrs(attr,skuId);
                //    保存sku的优惠满减等信息   sms_sku_ladder -> sms_sku_full_reduction -> sms_member_price
                SkuReductionTo skuReductionTo = new SkuReductionTo();
                BeanUtils.copyProperties(sku,skuReductionTo);
                skuReductionTo.setSkuId(skuId);
                //当满减信息有效时才进行远程调用
                if (skuReductionTo.getFullCount() > 0 || skuReductionTo.getFullPrice().compareTo(new BigDecimal("0")) == 1) {
                    R result = couponFeignService.saveSkuReduction(skuReductionTo);
                    if (result.getCode() != 0) {
                        log.error("远程保存优惠信息信息失败！");
                    }
                }
            });
        }
    }

    @Override
    public PageUtils pageSpuProductByCondition(Map<String, Object> params) {
        QueryWrapper<SpuInfoEntity> queryWrapper = new QueryWrapper<>();
        // 获取参数
        String key = (String) params.get("key");
        String status = (String) params.get("status");
        String brandId = (String) params.get("brandId");
        String catelogId = (String) params.get("catelogId");

        String curr = (String) params.get("page");
        long current = 1;
        if (curr != null) {
            current = Integer.parseInt(curr);
        }
        long limit = 1;
        String limitStr = (String) params.get("limit");
        if (limitStr != null) {
            limit = Integer.parseInt(limitStr);
        }

        //判空拼接对象
        if (!StringUtils.isEmpty(key)){
            queryWrapper.and((wrapper) -> {
                wrapper.eq("id",key).or().like("spu_name",key);
            });
        }
        if (!StringUtils.isEmpty(status)){
            queryWrapper.eq("publish_status",status);
        }
        if (!StringUtils.isEmpty(brandId)){
            queryWrapper.eq("brand_id",brandId);
        }
        if (!StringUtils.isEmpty(catelogId)){
            queryWrapper.eq("catalog_id",catelogId);
        }
        // 创建分页对象
        Page<SpuInfoEntity> page = new Page<>(current,limit);
        // 执行查询
        baseMapper.selectPage(page,queryWrapper);
        // 结果封装
        PageUtils pageUtils = new PageUtils(page.getRecords(),(int)page.getTotal(),(int)page.getSize(),(int)current);
        return pageUtils;
    }

    //TODO 上架时添加属性，这里还是没有解决，太他妈头疼了。

    // Spu上架
    @Override
    public void upSpu(Long spuId) {
        //1.查询当前spuId对应的所有Sku信息，品牌的名称
        List<SkuInfoEntity> skuInfoEntities = skuInfoService.getSkusBySpuId(spuId);
        List<Long> skuIds = skuInfoEntities.stream().map(SkuInfoEntity::getSkuId).collect(Collectors.toList()); //sku的id集合
        //2.查询spu的分类以及品牌信息
        SpuInfoEntity spuInfo = baseMapper.selectById(spuId);
        BrandEntity brand = brandService.getById(spuInfo.getBrandId()); //品牌信息
        CategoryEntity category = categoryService.getById(spuInfo.getCatalogId());  //分类信息
        //3.查询spu可以被检索的规格属性
        List<ProductAttrValueEntity> productAttrs = productAttrValueService.listAttrForSpu(spuId);  //spu所有的属性
        List<Long> attrIds = productAttrs.stream().map(item -> {
            return item.getAttrId();    //spu的属性id
        }).collect(Collectors.toList());
        List<Long> searchAttrs = attrService.selectSearchAttrs(attrIds); //查询可以被检索的属性id
        Set<Long> ids = new HashSet<>(searchAttrs); //将可以被检索的ids转换为set集合
        // 过滤出spu是可以被检索的属性
        List<ProductAttrValueEntity> collect = productAttrs.stream().filter(item -> {
            return ids.contains(item.getAttrId());
        }).collect(Collectors.toList());
        // 封装为EsModel中的属性对象
        List<SkuEsModel.Attrs> attrs = collect.stream().map(item -> {
            SkuEsModel.Attrs attr = new SkuEsModel.Attrs();
            BeanUtils.copyProperties(item,attr);
            return attr;
        }).collect(Collectors.toList());

        Map<Long, Boolean> hasStockMap = null;
        try {
            //4.远程调用查询是否含有库存 hasStock
            List<HasStockTo> hasStockTos = wareFeignService.hasStock(skuIds);
            //  把hasStock集合转换为map形式，其中key为hasStock的id，value为hasStock的值
            hasStockMap = hasStockTos.stream().collect(Collectors.toMap(HasStockTo::getSkuId, HasStockTo::getHasStock));
        } catch (Exception e) {
            log.error("库存服务查询出现异常：{}",e);
        }
        Map<Long, Boolean> finalHasStockMap = hasStockMap;
        //4.封装每一个sku的信息为SkuEsModel对象
        List<SkuEsModel> skuEsModels = skuInfoEntities.stream().map(sku -> {
            SkuEsModel esModel = new SkuEsModel();
            //属性对拷
            BeanUtils.copyProperties(sku,esModel);
            //设置skuPrice,skuImg,hasStock,hotScore,attrs
            esModel.setBrandId(brand.getBrandId());
            esModel.setBrandName(brand.getName());  //品牌名称
            esModel.setBrandImg(brand.getLogo());   //品牌logo
            esModel.setCatalogName(category.getName()); //分类名称
            esModel.setSkuPrice(sku.getPrice());    //sku价格
            esModel.setSkuImg(sku.getSkuDefaultImg());  //sku图片
            esModel.setAttrs(attrs);    //属性
            esModel.setHotScore(0L);    //热度
            if (finalHasStockMap == null){
                esModel.setHasStock(false);
            }else {
                esModel.setHasStock(finalHasStockMap.get(sku.getSkuId()));   //库存
            }
            return esModel;
        }).collect(Collectors.toList());
        //5.将所有的Sku数据发送给ES进行保存
        R result = searchFeignService.productStatusUp(skuEsModels);
        if (result.getCode() == 0){
            //远程调用成功，修改Spu的状态
            SpuInfoEntity entity = new SpuInfoEntity();
            entity.setId(spuId);    //spuId
            entity.setPublishStatus(ProductConstant.ProductStatusCode.ASSIGNED.getCode());  //状态改为上架
            entity.setUpdateTime(new Date());   //更新时间
            this.updateById(entity);
        }else {
            //远程调用失败
            //TODO 重复调用问题？接口幂等性？重试机制？后来再说。
            System.out.println("出问题啦！");
        }
    }

    @Override
    public SpuInfoVo getSpuInfoBySkuId(Long skuId) {
        SkuInfoEntity skuInfo = skuInfoService.getOne(new QueryWrapper<SkuInfoEntity>().eq("sku_id", skuId));
        Long spuId = skuInfo.getSpuId();
        SpuInfoEntity spuInfo = this.getOne(new QueryWrapper<SpuInfoEntity>().eq("id", spuId));
        SpuInfoVo spuInfoVo = new SpuInfoVo();
        BeanUtils.copyProperties(spuInfo,spuInfoVo);
        return spuInfoVo;
    }
}